/*
 * File:   AssRule.h
 * Author: wx
 *关联规则挖掘功能抽象
 * Created on 2009年12月20日, 下午3:36
 */

#ifndef _ASSRULE_H
#define	_ASSRULE_H

#include <string>
#include <fstream>
using namespace std;

#include "Transaction.h"
#include "FPNode.h"
#include "HeadTable.h"
#include "Pattern.h"
#include "FPTree.h"

class AssRule
{
private:
    string filename;
    string output;
    int threshold;
    vector<Transaction> vt;
    
public:
    static int OK = 0;
    static int FILE_OPEN_ERROR = -1;
    static int FILE_CREAT_ERROR = -2;

    AssRule(string name,string out,int thres)
    {
        filename = name;
        output = out;
        threshold = thres;
    }

    int Run()
    {
        ifstream fin(filename);
        if( !fin)
        {
            return FILE_OPEN_ERROR;
        }

        //get all the trasaction

        string line;
        while(getline(fin,line))
        {
            vt.push_back(Transaction(line));
        }

        //ht = new HeadTable(vt);

        //build tree
        FPTree * maintree = new FPTree(vt);

        //begin of rules mining

        //output all assrule
    }

private:    

    set<Pattern> FP_growth(FPNode * root,Pattern curset)
    {
        //先检查有没有single prefix path
        FPNode * single = NULL;
        FPNode * mutil = NULL;

        set<Pattern> singleresult;
        set<Pattern> mutilresult;

        makeTree(root,single,mutil);

        //如果有singlepath部分，从singlepath部分产生一部分频繁模式
        if( single != NULL)
        {
            singleresult = generatePatternSingle(single);
        }

        //mutil部分频繁模式挖掘
        //枚举mutil树中的每一个，生成一个模式b，然后再在此模式基础上建立conditional pattern base和conditional FP-TRee
        //如果建树非空，call FP_growth(Tree,b)
        //得到的所有结果并起来

        vector<FPNode *> mutilnodevec = getAllTreeNode(mutil);
        for( int i = 0;i < mutilnodevec.size();i++)
        {
            Pattern curpattern = curset;
            curpattern.addPattern(mutilnodevec[i].getItem());

            if( mutilnodevec[i].getCount() < threshold)continue;

            curpattern.setCount(mutilnodevec[i].getCount());

            //construct the conditional pattern base and the conditional FPTree
            //set<Pattern> tmppattern = getConditionalPattern(mutilnodevec[i].getItem(),mutil);
            //FPNode * tmproot = getConditionalTree(tmppattern);
            
            //here build a new PFTree
            

            set<Pattern> tmpresult = FP_growth(tmproot,curpattern);
            mutilresult.insert(tmpresult.begin(),tmpresult.end());
        }

        //把single部分和mutil部分合并，single+mutil+single*mutil
        set<Pattern> crossresult = crossPattern(singleresult,mutilresult);
        set<Pattern> result;
        result.insert(singleresult.begin(),singleresult.end());
        result.insert(mutilresult.begin(),mutilresult.end());
        result.insert(crossresult.begin(),crossresult.end());
        
        return result;
    }

    void makeTree(FPNode * root,FPNode * single, FPNode * mutil)
    {
        FPNode * tmproot = root;
        while( tmproot != NULL && tmproot->getChildCount() == 1)
        {
            tmproot = tmproot->getSingleNode();
        }

        if(tmproot->getChildCount() == 0)
        {
            mutil = NULL;
        }
        else
        {
            mutil = new FPNode(*tmproot);
        }

        if( tmproot = root)
        {
            single = NULL;
        }
        else
        {
            single = root;
            tmproot->clearChild();
        }
    }

    set<Transaction> generatePatternSingle(FPNode * root)
    {
        set<Transaction> result;

        //generate all combination of root
        //这里要有一个从n中枚举m的组合函数
        //并且还要根据阈值进行判断

        return result;
    }

    vector<FPNode *> getAllTreeNode(FPNode * root)
    {
        //广度优先遍历
        //root本身是没有意义的。
        int curlevelcount = root->getChildCount();
        vector<FPNode *> tmpv = root->getAllChild();
        vector<FPNode *> result;
        //here how insert?
        result.insert(result.begin(),tmpv.begin(),tmpv.end());

        while( curlevelcount > 0)
        {
            int tmpcount = 0;
            tmpv.clear();
            for( int i = 0;i < curlevelcount;i++)
            {
                vector<FPNode *> childnodes = result[i]->getAllChild();
                tmpcount += childnodes.size();
                tmpv.insert(tmpv.begin(),childnodes.begin(),childnodes.end());
            }
            result.insert(result.begin(),tmpv.begin(),tmpv.end());
            curlevelcount = tmpcount;
        }

        return result;
    }


    set<Pattern> crossPattern(set<Pattern> & single,set<Pattern> & mutil)
    {
        set<Pattern> result;
        for( set<Pattern>::iterator si = single.begin();si != single.end();si++)
        {
            for( set<Pattern>::iterator mi = mutil.begin();mi != mutil.end();mi++)
            {
                result.insert(Pattern(*si,*mi));
            }
        }
        return result;
    }
};

#endif	/* _ASSRULE_H */

